<!-- eslint-disable vue/html-indent -->
<template>
  <view class="audio-cc">
    <view class="info-box" style="padding-bottom: 0">
      <view class="title"> {{ title }} </view>
    </view>
    <slider
      style="margin-bottom: 0"
      class="audio-slider"
      activeColor="#000000"
      backgroundColor="#000000"
      block-color="#000000"
      block-size="12"
      :max="sliderMax"
      :value="sliderCurrent"
      @change="sliderChange"
      @changing="sliderChanging"
    />
    <view class="info-box" style="padding-top: 0; padding-bottom: 0">
      <view class="time">
        <view class="time-left">{{ timeLeft }}</view>
        <view class="time-right">{{ timeRight }}</view>
      </view>
    </view>
    <view class="info-box" style="padding-top: 0">
      <view class="img">
        <img
          class="play-btn"
          @click="changeState"
          mode="widthFix"
          :src="currentImg"
        />
      </view>
    </view>
  </view>
</template>

<script lang="ts" setup>
import {
  ref,
  computed,
  onMounted,
  onBeforeUnmount,
  defineProps,
  defineEmits
} from 'vue'

const props = defineProps({
  src: {
    type: String,
    default: ''
  },
  title: {
    type: String,
    default: ''
  },
  autoplay: {
    type: Boolean,
    default: false
  },
  loop: {
    type: Boolean,
    default: false
  },
  alonePlay: {
    type: Boolean,
    default: false
  },
  playImg: {
    type: String,
    default: '../../static/play.svg'
  },
  pauseImg: {
    type: String,
    default: '../../static/stop.svg'
  }
})

const emit = defineEmits(['ended'])
const max = ref<number>(0)
const current = ref<number>(0)
const play = ref<boolean>(false)
const innerAudioContext = ref<any>(null)
const accuracy = 3000
const ready = ref<boolean>(false)
const srcChange = ref<boolean>(false)
const audioInit = () => {
  if (props.src.length > 0) {
    const time = Math.floor(Date.now() / (1000 * 60 * 30))
    const src = `${props.src}?v=${time}`
    //加载之前先销毁之前的音频组件
    if (innerAudioContext.value) {
      try {
        innerAudioContext.value.pause()
        innerAudioContext.value.destroy()
        innerAudioContext.value = null
      } catch (e) {
        console.log('错误销毁',e);
      }
    }
    innerAudioContext.value = uni.createInnerAudioContext()
    innerAudioContext.value.autoplay = props.autoplay
    innerAudioContext.value.src = src
    innerAudioContext.value.loop = props.loop
    innerAudioContext.value.onPlay(() => {
      if (!play.value) {
        playAudio()
      }
      if (props.alonePlay) {
        // 暂停其他音频
      }
    })
    innerAudioContext.value.onCanplay(() => {
      ready.value = true
      max.value = innerAudioContext.value.duration
    })

    innerAudioContext.value.onTimeUpdate(() => {
      if (srcChange.value) {
        srcChange.value = false
        max.value = innerAudioContext.value.duration
      }
      current.value = innerAudioContext.value.currentTime
    })

    innerAudioContext.value.onPause(() => {
      if (play.value) {
        pauseAudio()
      }
    })

    innerAudioContext.value.onEnded(() => {
      stopAudio()
      emit('ended')
    })

    innerAudioContext.value.onError(err => {
      ready.value = false
      const errorMap: Record<number, string> = {
        10001: '系统错误',
        10002: '网络错误',
        10003: '文件错误',
        10004: '格式错误',
        '-1': '文件加载失败'
      }
      const errorMsg = errorMap[err.code ?? -1] || '未知错误'
      uni.showToast({ title: errorMsg, icon: 'error' })
    })
  }
}

const changeState = () => {
  console.log(ready.value, play.value)

  if (ready.value) {
    play.value ? pauseAudio() : playAudio()
  } else {
    uni.showToast({ title: '音频加载失败请更换源' })
  }
}

const playAudio = () => {
  play.value = true
  innerAudioContext.value.play()
}

const pauseAudio = () => {
  console.log('进入暂停', innerAudioContext.value)

  play.value = false
  innerAudioContext.value.pause()
}

const stopAudio = () => {
  innerAudioContext.value.stop()
  play.value = false
  current.value = 0
}

const seek = (index: number) => {
  innerAudioContext.value.seek(index / accuracy)
}

const sliderChange = (e: any) => {
  pauseAudio()
  seek(e.detail.value)
  playAudio()
}

const sliderChanging = () => {
  pauseAudio()
}

const currentImg = computed(() => (play.value ? props.pauseImg : props.playImg))
const timeLeft = computed(() => {
  if (current.value <= 0) return '00:00'
  const end = current.value
  const minute = Math.floor(end / 60)
    .toString()
    .padStart(2, '0')
  const second = Math.floor(end % 60)
    .toString()
    .padStart(2, '0')
  return `${minute}:${second}`
})
const timeRight = computed(() => {
  if (max.value <= 0) return '00:00'
  const end = max.value
  const minute = Math.floor(end / 60)
    .toString()
    .padStart(2, '0')
  const second = Math.floor(end % 60)
    .toString()
    .padStart(2, '0')
  return `${minute}:${second}`
})
const sliderMax = computed(() =>
  max.value > 0 ? Math.floor(max.value * accuracy) : 0
)
const sliderCurrent = computed(() =>
  current.value > 0 ? Math.floor(current.value * accuracy) : 0
)

onMounted(() => {
  audioInit()
})

onBeforeUnmount(() => {
  innerAudioContext.value.stop()
  innerAudioContext.value.destroy()
})
</script>

<style lang="scss">
.audio-cc {
  width: 100%;
  background: #f9f9f9;
  border-radius: 16rpx;
  position: relative;

  .info-box {
    width: 90%;
    padding: 20rpx 30rpx;

    .title {
      height: 40rpx;
      font-size: 28rpx;
      font-family: PingFangSC-Regular, PingFang SC;
      font-weight: 400;
      color: #262626;
      line-height: 40rpx;
      text-align: center;
    }

    .time {
      width: 100%;
      display: flex;
      color: #ccc;
      .time-left {
        flex: 1;
      }
      .time-right {
        flex: 1;
        text-align: right;
      }
    }
    .img {
      text-align: center;
      image {
        width: 60rpx;
        height: 60rpx;
      }
    }
  }

  .audio-slider {
    width: 90%;
  }
}
</style>
